home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / termutil.0 / termutil / termutils-2.0 / tput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  12.4 KB  |  584 lines

  1. /* tput -- shell-level interface to terminfo, emulated by termcap.
  2.    Copyright (C) 1991, 1995 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Usage: tput [-T termtype] [--terminal=termtype] capability [parameter...]
  19.  
  20.    Options:
  21.    -T termtype
  22.    --terminal=termtype    Override $TERM.
  23.  
  24.    Requires the GNU termcap library.
  25.    Requires the bsearch library function and GNU getopt.
  26.  
  27.    Written by David MacKenzie <djm@gnu.ai.mit.edu> and
  28.    Junio Hamano <junio@twinsun.com>.  */
  29.  
  30. #include <config.h>
  31. #include <stdio.h>
  32. #include <termcap.h>
  33. #include <getopt.h>
  34. #include <errno.h>
  35.  
  36. #if STDC_HEADERS || HAVE_STRING_H
  37. # include <string.h>
  38. #else
  39. # include <strings.h>
  40. # define strrchr rindex
  41. #endif
  42.  
  43. #if STDC_HEADERS
  44. # include <stdlib.h>
  45. #else
  46. char *getenv ();
  47. #endif
  48.  
  49. #include <tcutil.h>
  50. #include <tput.h>
  51.  
  52. #ifndef errno
  53. extern int errno;
  54. #endif
  55.  
  56. /* Exit codes. */
  57. #define CAP_PRESENT 0        /* Normal operation. */
  58. #define BOOLEAN_FALSE 1        /* Boolean capability not present. */
  59. #define USAGE_ERROR 2        /* Invalid arguments given. */
  60. #define UNKNOWN_TERM 3        /* $TERM not found in termcap file. */
  61. #define MISSING_CAP 4        /* Termcap entry lacks this capability. */
  62. #define ERROR_EXIT 5        /* Real error or signal. */
  63.  
  64. void error ();
  65. int tcputchar ();
  66. void tput_one_item ();
  67. void put_bool ();
  68. void put_num ();
  69. void put_str ();
  70. void put_longname ();
  71. void put_reset ();
  72. void put_init ();
  73. void put_init_internal ();
  74. void setup_termcap ();
  75. void split_args ();
  76. void usage ();
  77. void version ();
  78.  
  79. char *fgetline ();
  80.  
  81. extern char *version_string;
  82.  
  83. /* The name this program was run with, for error messages. */
  84. char *program_name;
  85.  
  86. /* Take capability from stdin */
  87. static int use_standard_input;
  88.  
  89. /* Use termcap name only */
  90. static int use_termcap_only;
  91.  
  92. static struct option long_options[] =
  93. {
  94.   {"help", no_argument, 0, 'h'},
  95.   {"standard-input", no_argument, 0, 'S'},
  96.   {"terminal", required_argument, 0, 'T'},
  97.   {"termcap", no_argument, 0, 't'},
  98.   {"version", no_argument, 0, 'V'},
  99.   {0, 0, 0, 0}
  100. };
  101.  
  102. void
  103. main (argc, argv)
  104.      int argc;
  105.      char **argv;
  106. {
  107.   char *term;            /* Terminal type. */
  108.   int c;            /* Option character. */
  109.  
  110.   program_name = argv[0];
  111.   term = getenv ("TERM");
  112.   use_standard_input = 0;
  113.   use_termcap_only = 0;
  114.  
  115.   while ((c = getopt_long (argc, argv, "T:SV",
  116.                long_options, (int *) 0)) != EOF)
  117.     {
  118.       switch (c)
  119.     {
  120.     case 'h':
  121.       usage (stdout, 0);
  122.       break;
  123.     case 't':
  124.       use_termcap_only = 1;
  125.       break;
  126.     case 'T':
  127.       term = optarg;
  128.       break;
  129.     case 'S':
  130.       use_standard_input = 1;
  131.       break;
  132.     case 'V':
  133.       version ();
  134.       break;
  135.     default:
  136.       usage (stderr, 1);
  137.     }
  138.     }
  139.  
  140.   if ((use_standard_input && (optind != argc)) ||
  141.       ((use_standard_input == 0) && (optind == argc)))
  142.     usage (stderr, 1);
  143.  
  144.   setup_termcap (term);
  145.  
  146.   if (use_standard_input)
  147.     {
  148.       /* max number of args is 9 (sgr), even
  149.      though we use only 4 of them for now. */
  150.       char *line;
  151.       char *argbuf[10];
  152.       int argcount;
  153.       while ((line = fgetline (stdin)) != NULL)
  154.     {
  155.       argcount = sizeof (argbuf) / sizeof (argbuf[0]);
  156.       split_args (line, argbuf, &argcount);
  157.       tput_one_item (argbuf, argcount);
  158.       free (line);
  159.     }
  160.     }
  161.   else
  162.     tput_one_item (argv + optind, argc - optind);
  163.   exit (CAP_PRESENT);
  164. }
  165.  
  166. void
  167. tput_one_item (argv, argc)
  168.      char **argv;
  169.      int argc;
  170. {
  171.   struct conversion *conv;
  172.  
  173.   conv = find_info (argv[0], use_termcap_only);
  174.   if (conv == NULL)
  175.     {
  176.       if (strcmp (argv[0], "longname") == 0)
  177.     put_longname ();
  178.       else if (strcmp (argv[0], "reset") == 0)
  179.     put_reset ();
  180.       else if (strcmp (argv[0], "init") == 0)
  181.     put_init ();
  182.       else
  183.     {
  184.       error (MISSING_CAP, 0, "Unknown term%s capability `%s'",
  185.          use_termcap_only ? "cap" : "info", argv[0]);
  186.     }
  187.       if (use_standard_input)
  188.     return;
  189.       else
  190.     exit (CAP_PRESENT);
  191.     }
  192.  
  193.   if (conv->type & NUM)
  194.     put_num (conv, use_standard_input);
  195.   else if (conv->type & BOOL)
  196.     put_bool (conv, use_standard_input);
  197.   else
  198.     put_str (conv, argv + 1, argc - 1);
  199. }
  200.  
  201. void
  202. put_num (conv)
  203.      struct conversion *conv;
  204. {
  205.   if (use_standard_input)
  206.     {
  207.       error (USAGE_ERROR, 0,
  208.          "Number capability `%s' cannot be used with -S", conv->info);
  209.     }
  210.   printf ("%d\n", tgetnum (conv->cap));
  211. }
  212.  
  213. void
  214. put_bool (conv)
  215.      struct conversion *conv;
  216. {
  217.   if (use_standard_input)
  218.     {
  219.       error(USAGE_ERROR, 0,
  220.         "Boolean capability `%s' cannot be used with -S", conv->info);
  221.     }
  222.   if (!tgetflag (conv->cap))
  223.     exit (BOOLEAN_FALSE);
  224. }
  225.  
  226. void
  227. put_str (conv, argv, argc)
  228.      struct conversion *conv;
  229.      char **argv;
  230.      int argc;
  231. {
  232.   char *string_value;        /* String capability. */
  233.   int lines_affected;        /* Number of lines affected by capability. */
  234.  
  235.   string_value = tgetstr (conv->cap, (char **) NULL);
  236.   if (string_value == NULL)
  237.     if (use_standard_input)
  238.       return;
  239.     else
  240.       exit (MISSING_CAP);
  241.  
  242.   if (!strcmp (conv->cap, "cm"))
  243.     {
  244.       if (BC == 0)
  245.     BC = tgetstr ("le", (char **) NULL);
  246.       if (UP == 0)
  247.     UP = tgetstr ("up", (char **) NULL);
  248.  
  249.       /* The order of command-line arguments is `vertical horizontal'.
  250.      If horizontal is not given, it defaults to 0. */
  251.       switch (argc)
  252.     {
  253.     case 0:
  254.       break;
  255.     case 1:
  256.       string_value = tgoto (string_value, 0, atoi (argv[0]));
  257.       break;
  258.     default:
  259.       string_value = tgoto (string_value,
  260.                 atoi (argv[1]), atoi (argv[0]));
  261.       break;
  262.     }
  263.     }
  264.   else
  265.     /* Although the terminfo `sgr' capability can take 9 parameters,
  266.        the GNU tparam function only accepts up to 4.
  267.        I don't know whether tparam could interpret an `sgr'
  268.        capability reasonably even if it could accept that many
  269.        parameters.  For now, we'll live with the 4-parameter limit. */
  270.     switch (argc)
  271.       {
  272.       case 0:
  273.     break;
  274.       case 1:
  275.     string_value = tparam (string_value, (char *) NULL, 0,
  276.                    atoi (argv[0]));
  277.     break;
  278.       case 2:
  279.     string_value = tparam (string_value, (char *) NULL, 0,
  280.                    atoi (argv[0]),
  281.                    atoi (argv[1]));
  282.     break;
  283.       case 3:
  284.     string_value = tparam (string_value, (char *) NULL, 0,
  285.                    atoi (argv[0]),
  286.                    atoi (argv[1]),
  287.                    atoi (argv[2]));
  288.     break;
  289.       default:
  290.     string_value = tparam (string_value, (char *) NULL, 0,
  291.                    atoi (argv[0]),
  292.                    atoi (argv[1]),
  293.                    atoi (argv[2]),
  294.                    atoi (argv[3]));
  295.     break;
  296.       }
  297.  
  298.   /* Since we don't know where the cursor is, we have to be
  299.      pessimistic for capabilities that need padding proportional to
  300.      the number of lines affected, and tell them that the whole
  301.      screen is affected.  */
  302.   if (conv->type & PAD)
  303.     lines_affected = tgetnum ("li");
  304.   else
  305.     lines_affected = 1;
  306.  
  307.   if (lines_affected < 1)
  308.     lines_affected = 1;
  309.  
  310.   translations_off ();
  311.   tputs (string_value, lines_affected, tcputchar);
  312.   fflush (stdout);
  313.   restore_translations ();
  314. }
  315.  
  316. /* Output function for tputs.  */
  317.  
  318. int
  319. tcputchar (c)
  320.      char c;
  321. {
  322.   putchar (c & 0x7f); /* do we still need masking? */
  323.   return c;
  324. }
  325.  
  326. /* Although GNU termcap can dynamically allocate the buffer,
  327.    we need to use static allocation to extract the longname
  328.    ourselves. */
  329. static char term_buffer[2048];
  330.  
  331. void
  332. put_longname ()
  333. {
  334.   char *ep, *cp;
  335.   for (ep = term_buffer; *ep && *ep != ':'; ep++)
  336.     ;
  337.   cp = (char *) xmalloc (ep - term_buffer + 1);
  338.   strncpy (cp, term_buffer, ep - term_buffer);
  339.   cp[ep - term_buffer] = 0;
  340.   for (ep = &cp[ep - term_buffer] - 1; ep >= cp && *ep != '|'; ep--)
  341.     ;
  342.   if (ep >= cp && *ep == '|')
  343.     puts (ep + 1);
  344.   else
  345.     puts (cp);
  346. }
  347.  
  348. void
  349. put_init_internal (reset)
  350.      int reset;
  351. {
  352.   int need_xtabs;
  353.   int lines, it;
  354.   char *cap;
  355.  
  356.   need_xtabs = 0;
  357.  
  358.   lines = tgetnum ("li");
  359.   if (lines <= 0)
  360.     lines = 25;
  361.  
  362.   /* Disable OPOST */
  363.   translations_off ();
  364.  
  365.   /* Output "rs" if we are resetting */
  366.   cap = tgetstr ("rs", (char **) NULL);
  367.   if (cap)
  368.     tputs (cap, lines, tcputchar);
  369.  
  370.   /* Output "i1" */
  371.   cap = tgetstr ("i1", (char **) NULL);
  372.   if (cap)
  373.     tputs (cap, lines, tcputchar);
  374.  
  375.   /* Output "is" */
  376.   cap = tgetstr ("is", (char **) NULL);
  377.   if (cap)
  378.     tputs (cap, lines, tcputchar);
  379.  
  380.   /* Output "if" */
  381.   cap = tgetstr ("if", (char **) NULL);
  382.   if (cap)
  383.     {
  384.       char buf[1024];
  385.       int fd;
  386.       int nbytes;
  387.       int errors;
  388.  
  389.       errors = 0;
  390.       fd = open (cap, 0);
  391.       if (fd >= 0)
  392.     {
  393.       while ((nbytes = read (fd, buf, sizeof (buf))) > 0)
  394.         {
  395.           if (write (1, buf, nbytes) < 0)
  396.         {
  397.           error (0, errno, "cannot write initialization string");
  398.           errors++;
  399.           break;
  400.         }
  401.         }
  402.       close (fd);
  403.     }
  404.       else
  405.     {
  406.       error (0, errno, "cannot read initialization file `%s'", cap);
  407.       errors++;
  408.     }
  409.       if (errors)
  410.     {
  411.       restore_translations ();
  412.       exit (ERROR_EXIT);
  413.     }
  414.     }
  415.  
  416.   /* Output "i3" */
  417.   cap = tgetstr ("i3", (char **) NULL);
  418.   if (cap)
  419.     tputs (cap, lines, tcputchar);
  420.  
  421.   /* Check "it".
  422.        If it is not 8, then
  423.          check "ct" and "st".
  424.      If both present, then
  425.        Output "ct", followed by `\r' (or `cr' if set),
  426.        followed by eight (8) spaces, followed by `st',...
  427.        until we reach `co' (or winsize if exist, or 80)
  428.      else
  429.        Remember that we should enable XTABS
  430.        fi */
  431.  
  432.   it = tgetnum ("it");
  433.   if (it < 0 || it == 8)
  434.     ;                /* Assume standard setting is 8 */
  435.   else
  436.     {
  437.       char *ct, *st;
  438.       if ((ct = tgetstr ("ct", (char **) NULL)) != 0 &&
  439.       (st = tgetstr ("st", (char **) NULL)) != 0)
  440.     {
  441.       int width, col;
  442.       char *cr;
  443.  
  444.       width = tgetnum ("co");
  445.       if (width <= 0)
  446.         {
  447.           /* NEEDSWORK: we may want to find out how
  448.            wide the window is using newer tty structures. */
  449.           width = 80;
  450.         }
  451.       if ((cr = tgetstr ("cr", (char **) NULL)) == 0)
  452.         cr = "\r";
  453.       tputs (cr, lines, tcputchar);
  454.       for (col = 1; col < width; col += 8)
  455.         {
  456.           tputs ("        ", 1, tcputchar);
  457.           tputs (st, 1, tcputchar);
  458.         }
  459.     }
  460.       else
  461.     need_xtabs = 1;
  462.     }
  463.  
  464.   fflush (stdout);
  465.   /* Enable OPOST. */
  466.   restore_translations ();
  467.  
  468.   /* If we should enable XTABS, do it. */
  469.   if (need_xtabs)
  470.     enable_xtabs ();
  471. }
  472.  
  473. void
  474. put_reset ()
  475. {
  476.   put_init_internal (1);
  477. }
  478.  
  479. void
  480. put_init ()
  481. {
  482.   put_init_internal (0);
  483. }
  484.  
  485. /* Read in the needed termcap strings for terminal type TERM. */
  486.  
  487. void
  488. setup_termcap (term)
  489.      char *term;
  490. {
  491.   char *tc_pc;            /* "pc" termcap string. */
  492.  
  493.   if (term == NULL)
  494.     error (UNKNOWN_TERM, 0, "No value for $TERM and no -T specified");
  495.   switch (tgetent (term_buffer, term))
  496.     {
  497.     case 0:
  498.       error (UNKNOWN_TERM, 0, "Unknown terminal type `%s'", term);
  499.     case -1:
  500.       error (UNKNOWN_TERM, 0, "No termcap database");
  501.     }
  502.  
  503.   tc_pc = tgetstr ("pc", (char **) NULL);
  504.   PC = tc_pc ? *tc_pc : 0;
  505. }
  506.  
  507. void
  508. split_args (buf, argv, argc)
  509.      char *buf;
  510.      char **argv;
  511.      int *argc;
  512. {
  513.   int maxargs = *argc - 1;
  514.   int argindex = 0;
  515.  
  516.   while (*buf && *buf != '\n' && argindex < maxargs)
  517.     {
  518.       /* Skip leading blanks */
  519.       while (*buf == ' ' || *buf == '\t')
  520.     buf++;
  521.       if (*buf == 0 || *buf == '\n')
  522.     {
  523.       *argc = argindex;
  524.       return;
  525.     }
  526.       argv[argindex] = buf;
  527.       /* Skip to next blank */
  528.       while (*buf && *buf != '\n' && *buf != ' ' && *buf != '\t')
  529.     buf++;
  530.       if (*buf == 0)
  531.     {
  532.       *argc = argindex;
  533.       return;
  534.     }
  535.       else
  536.     {
  537.       *buf++ = 0;
  538.     }
  539.       argindex++;
  540.     }
  541.   *argc = argindex;
  542. }
  543.  
  544. void
  545. usage (stream, status)
  546.      FILE *stream;
  547.      int status;
  548. {
  549.   static char *how[] =
  550.   {
  551.     "Usage: [options] capability [parameters...]",
  552.     "       [options] longname",
  553.     "       [options] init",
  554.     "       [options] reset",
  555.     0,
  556.   };
  557.   static char *opts[] =
  558.   {
  559.     "       [-T termtype] [--terminal=termtype] : specify terminal type",
  560.     "       [-t] [--termcap] : search only by termcap name",
  561.     "       [-V] [--version] : print version information",
  562.     "       [-S] [--standard-input] : read capabilities from standard input",
  563.     0,
  564.   };
  565.   char **p;
  566.  
  567.   for (p = how; *p; p++)
  568.     fprintf (stderr, "%s\n", *p);
  569.   fprintf (stream, "Options:\n");
  570.   for (p = opts; *p; p++)
  571.     fprintf (stream, "%s\n", *p);
  572.   if (status)
  573.     exit (USAGE_ERROR);
  574.   else
  575.     exit (0);
  576. }
  577.  
  578. void
  579. version ()
  580. {
  581.   printf ("GNU tput version %s\n", version_string);
  582.   exit (0);
  583. }
  584.